package ru.usu.gv.uicomponents;

import ru.usu.gv.core.GraphCanvas;
import ru.usu.gv.core.GraphEngine;
import ru.usu.gv.graph.Vertex;
import ru.usu.gv.styles.StyleConstants;
import ru.usu.gv.styles.StyleFacade;
import ru.usu.gv.uicomponents.viewitems.vertex.IVertexViewItem;
import ru.usu.gv.utils.GeometryUtil;
import ru.usu.gv.utils.StringUtilities;

import javax.media.j3d.Appearance;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Material;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.vecmath.Color3f;
import javax.vecmath.Point2d;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;

import java.awt.Color;

/**
 @author: Sergey Pupyrev 
 Apr 2, 2006
 */

public class UIVertex extends UIElementBase<IVertexViewItem>
{
	private IVertexViewItem viewItem;
	private IUIVertexType vertexType;
	private Point3d position;
	private String label;
	private Vertex vertex;

	public UIVertex(Point3d position)
	{
		this(position, StyleFacade.getVertexType());
	}

	public UIVertex(Point3d position, String vertexTypeId)
	{
		super();
		this.position = position;
		vertexType = UIVertexTypeRegistry.findVertexType(vertexTypeId);
		initializeView();
	}

	private void initializeView()
	{
		Appearance appearance = getAppearance();

		getTransformGroup().setTransform(calculateTransform());

		setMaterialColors(getMaterial());

		viewItem = vertexType.createVertexViewItem(appearance, getTransformGroup());
		viewItem.makePickable(this);
		viewItem.setColor(StyleFacade.getVertexColor());
		viewItem.setSize(StyleFacade.getVertexSize());
	}

	private void setMaterialColors(Material material)
	{
		material.setAmbientColor(new Color3f(0.0f, 0.0f, 0.4f));
		material.setEmissiveColor(new Color3f(0.0f, 0.0f, 0.0f));
		material.setDiffuseColor(new Color3f(StyleFacade.getVertexColor()));
		material.setSpecularColor(new Color3f(1.0f, 1.0f, 1.0f));
		material.setShininess(100.0f);
	}

	public String getLabel()
	{
		return label;
	}

	public void setLabel(String newLabel)
	{
		if (StringUtilities.equal(label, newLabel))
			return;

		label = newLabel;
		if (!StyleFacade.isShowVertexLabel())
			return;

		showLabel();
	}

	public void showLabel()
	{
		BranchGroup labelBranchGroup = getLabelBranch();
		labelBranchGroup = UIUtilities.addVertexLabel(label, labelBranchGroup);
		setLabelBranch(labelBranchGroup);
	}

	public void hideLabel()
	{
		BranchGroup labelSubBranch = UIUtilities.addVertexLabel(null, getLabelBranch());
		setLabelBranch(labelSubBranch);
	}

	public Vertex getVertex()
	{
		return vertex;
	}

	public void setVertex(Vertex vertex)
	{
		this.vertex = vertex;
	}

	public Point3d getPosition()
	{
		return position;
	}

	//TODO:
	//how to listen ui-changes???
	public void setPosition(Point3d position)
	{
		if (this.position.equals(position))
			return;

		this.position = position;
		GraphEngine.getInstance().getUIGraphListeners().doChange(this);
	}

	@Override
	public void draw()
	{
		super.draw();
		getTransformGroup().setTransform(calculateTransform());
	}

	private Transform3D calculateTransform()
	{
		Transform3D transform = new Transform3D();
		transform.setTranslation(new Vector3d(getPosition()));
		if (getViewItem() != null)
			transform.setScale(getViewItem().getSize() / StyleFacade.getDefaultDoubleAttribute(StyleConstants.VERTEX_SIZE_ATTRIBUTE));
		//add
		return transform;
	}

	public void moveToCanvasPosition(int x, int y)
	{
		Point2d hitPosition = new Point2d(x, y);
		Point3d newPosition = GeometryUtil.canvasToVWorldPosition(new Point3d(getPosition()), hitPosition, getTransformGroup());
		setPosition(newPosition);
	}

	@Override
	public void delete()
	{
		super.delete();
		GraphCanvas.getInstance().getCurrentGraph().removeVertex(this);
	}

	@Override
	public void highlight()
	{
		getAppearance().setMaterial(UIConstants.highlightMaterial);
	}

	@Override
	public void unhighlight()
	{
		getAppearance().setMaterial(getMaterial());
	}

	@Override
	public IVertexViewItem getViewItem()
	{
		return viewItem;
	}

	public IUIVertexType getVertexType()
	{
		return vertexType;
	}

	public void changeVertexType(IUIVertexType vertexType)
	{
		this.vertexType = vertexType;

		//recreate BranchGroup
		BranchGroup newBranchGroup = createBranchGroup();
		TransformGroup newTransformGroup = createTransformGroup(newBranchGroup);

		Transform3D transform3D = new Transform3D();
		getTransformGroup().getTransform(transform3D);
		newTransformGroup.setTransform(transform3D);

		//create new ViewItem
		Color oldColor = viewItem.getColor();
		double oldSize = viewItem.getSize();
		viewItem = vertexType.createVertexViewItem(getAppearance(), newTransformGroup);
		viewItem.makePickable(this);
		viewItem.setColor(oldColor);
		viewItem.setSize(oldSize);

		//remove old BranchGroup
		super.delete();

		//add new one
		setBranchGroup(newBranchGroup);
		setTransformGroup(newTransformGroup);
		initBranchGroup();
		if (StyleFacade.isShowVertexLabel())
			showLabel();
	}

	@Override
	public String toString()
	{
		if (StringUtilities.isEmpty(label))
			return String.valueOf(vertex.getIndex());
		return label;
	}
}
